// 《围棋》作者版权所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 此文件实现标识符和类型表达式的类型检查。

package types2

import (
	"cmd/compile/internal/syntax"
	"fmt"
	"go/constant"
	"strings"
)

// ident type检查标识符e，并用e的值或类型初始化x。
// 如果发生错误，x.mode将设置为无效。
// 有关def的含义，请参阅Checker。定义类型，如下。
// 如果设置了wantType，则标识符e应表示类型。注意我们不能使用check。在此处查找，因为返回的作用域
func (check *Checker) ident(x *operand, e *syntax.Name, def *Named, wantType bool) {
	x.mode = invalid
	x.expr = e

	// 可能与obj不同。父项（）。另见范围。看医生。
	scope, obj := check.scope.LookupParent(e.Value, check.pos)
	switch obj {
	case nil:
		if e.Value == "_" {
			// 从未声明空标识符，但当前标识符可能是接收器类型参数的占位符。在这种情况下，我们可以从Checker中解析它的类型和对象。记录地图。
			if tpar := check.recvTParamMap[e]; tpar != nil {
				x.mode = typexpr
				x.typ = tpar
			} else {
				check.error(e, "cannot use _ as value or type")
			}
		} else {
			if check.conf.CompilerErrorMessages {
				check.errorf(e, "undefined: %s", e.Value)
			} else {
				check.errorf(e, "undeclared name: %s", e.Value)
			}
		}
		return
	case universeAny, universeComparable:
		if !check.allowVersion(check.pkg, 1, 18) {
			check.errorf(e, "undeclared name: %s (requires version go1.18 or later)", e.Value)
			return // 避免后续错误
		}
	}
	check.recordUse(e, obj)

	// 键入检查对象。
	// 仅呼叫检查。objDecl如果对象还没有类型
	// （在这种情况下，我们必须实际确定它），或者该对象是
	// TypeName，我们还需要一个类型（在这种情况下，我们可能会检测到
	// /需要报告的循环）。否则，我们可以跳过
	// 调用，并避免可能的循环错误，以支持该函数的调用方
	// 将发出的更具信息性的“非类型/值”错误（请参见问题#25790）。
	typ := obj.Type()
	if _, gotType := obj.(*TypeName); typ == nil || gotType && wantType {
		check.objDecl(obj, def)
		typ = obj.Type() // 类型必须由检查者分配。objDecl 
	}
	assert(typ != nil)

	// 该对象可能已被点导入。
	// 如果是，请将相应的包装标记为已使用。
	// （此代码仅适用于dot导入。没有它们，
	// 我们只需标记变量，请参见下面的*Var case）。
	if pkgName := check.dotImportMap[dotImportKey{scope, obj.Name()}]; pkgName != nil {
		pkgName.used = true
	}

	switch obj := obj.(type) {
	case *PkgName:
		check.errorf(e, "use of package %s not in selector", obj.name)
		return

	case *Const:
		check.addDeclDep(obj)
		if typ == Typ[Invalid] {
			return
		}
		if obj == universeIota {
			if check.iota == nil {
				check.error(e, "cannot use iota outside constant declaration")
				return
			}
			x.val = check.iota
		} else {
			x.val = obj.val
		}
		assert(x.val != nil)
		x.mode = constant_

	case *TypeName:
		if check.isBrokenAlias(obj) {
			check.errorf(e, "invalid use of type alias %s in recursive type (see issue #50729)", obj.name)
			return
		}
		x.mode = typexpr

	case *Var:
		// 可以标记非局部变量，但忽略其他包中的变量
		// 以避免与
		// 点导入变量的潜在竞争条件。
		if obj.pkg == check.pkg {
			obj.used = true
		}
		check.addDeclDep(obj)
		if typ == Typ[Invalid] {
			return
		}
		x.mode = variable

	case *Func:
		check.addDeclDep(obj)
		x.mode = value

	case *Builtin:
		x.id = obj.id
		x.mode = builtin

	case *Nil:
		x.mode = nilvalue

	default:
		unreachable()
	}

	x.typ = typ
}

// typ type检查类型表达式e并返回其类型，或typ[Invalid]。
// 该类型不能是（未实例化的）泛型类型。
func (check *Checker) typ(e syntax.Expr) Type {
	return check.definedType(e, nil)
}

// varType type检查类型表达式e并返回其类型，或类型[Invalid]。
// 类型不能是（未实例化的）泛型类型，也不能是
// 约束接口。
func (check *Checker) varType(e syntax.Expr) Type {
	typ := check.definedType(e, nil)
	check.validVarType(e, typ)
	return typ
}

// 如果typ是约束接口，ValidPartnerType将报告错误。
// 表达式e用于错误报告（如果有）。
func (check *Checker) validVarType(e syntax.Expr, typ Type) {
	// 如果我们有一个类型参数，那就没什么可做的了。
	if isTypeParam(typ) {
		return
	}

	// 当我们在
	// 类型检查参数声明中间时，我们不想调用under（）或完整的接口，这些声明可能属于接口方法。将此检查延迟到类型检查结束。这是正确的位置吗？
	check.later(func() {
		if t, _ := under(typ).(*Interface); t != nil {
			pos := syntax.StartPos(e)
			if !tset.IsMethodSet() {
				if tset.comparable {
					check.softErrorf(pos, "interface is (or embeds) comparable")
				} else {
					check.softErrorf(pos, "interface contains type constraints")
				}
			}
		}
	})
}

// definedType与typ类似，但也接受类型名def。
// 如果定义！=nil，e是定义的类型def、在类型声明中声明的
// 和def的类型规范。在
// 检查e的任何组件之前，将基础设置为e的类型。
// 
func (check *Checker) definedType(e syntax.Expr, def *Named) Type {
	typ := check.typInternal(e, def)
	assert(isTyped(typ))
	if isGeneric(typ) {
		check.errorf(e, "cannot use generic type %s without instantiation", typ)
		typ = Typ[Invalid]
	}
	check.recordTypeAndValue(e, typexpr, typ, nil)
	return typ
}

// genericType与typ类似，但类型必须是（未实例化的）泛型类型。
func (check *Checker) genericType(e syntax.Expr, reportErr bool) Type {
	typ := check.typInternal(e, nil)
	assert(isTyped(typ))
	if typ != Typ[Invalid] && !isGeneric(typ) {
		if reportErr {
			check.errorf(e, "%s is not a generic type", typ)
		}
		typ = Typ[Invalid]
	}
	// TODO（gri）下面正确的呼叫是什么？
	check.recordTypeAndValue(e, typexpr, typ, nil)
	return typ
}

// goTypeName返回typ的Go类型名称，
// 删除所有出现的“types2”从那个名字开始。
func goTypeName(typ Type) string {
	return strings.Replace(fmt.Sprintf("%T", typ), "types2.", "", -1) // 字符串。ReplaceAll在Go 1.4 
}

// 类型的内部驱动器类型检查中不可用。
// 只能由definedType或genericType调用。
// 
func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) {
	if check.conf.Trace {
		check.trace(e0.Pos(), "-- type %s", e0)
		check.indent++
		defer func() {
			check.indent--
			var under Type
			if T != nil {
				// 在（）下调用可能会导致无尽的实例化。
				// 测试用例：类型T[P any]*T[P]
				under = safeUnderlying(T)
			}
			if T == under {
				check.trace(e0.Pos(), "=> %s // /%s，T，goTypeName（T））
			} else {
				check.trace(e0.Pos(), "=> %s (under = %s) // /%s，在，goTypeName（T））
			}
		}()
	}

	switch e := e0.(type) {
	case *syntax.BadExpr:
		// 忽略-在

	case *syntax.Name:
		var x operand
		check.ident(&x, e, def, true)

		switch x.mode {
		case typexpr:
			typ := x.typ
			def.setUnderlying(typ)
			return typ
		case invalid:
			// 忽略-在
		case novalue:
			check.errorf(&x, "%s used as type", &x)
		default:
			check.errorf(&x, "%s is not a type", &x)
		}

	case *syntax.SelectorExpr:
		var x operand
		check.selector(&x, e, def)

		switch x.mode {
		case typexpr:
			typ := x.typ
			def.setUnderlying(typ)
			return typ
		case invalid:
			// 忽略-在
		case novalue:
			check.errorf(&x, "%s used as type", &x)
		default:
			check.errorf(&x, "%s is not a type", &x)
		}

	case *syntax.IndexExpr:
		if !check.allowVersion(check.pkg, 1, 18) {
			check.versionErrorf(e.Pos(), "go1.18", "type instantiation")
		}
		return check.instantiatedType(e.X, unpackExpr(e.Index), def)

	case *syntax.ParenExpr:
		// 之前报告的错误必须先实例化泛型类型，然后才能以任何形式使用。
		// 因此，泛型类型不能用括号括起来。
		return check.definedType(e.X, def)

	case *syntax.ArrayType:
		typ := new(Array)
		def.setUnderlying(typ)
		if e.Len != nil {
			typ.len = check.arrayLength(e.Len)
		} else {
			// /[…]数组
			check.error(e, "invalid use of [...] array (outside a composite literal)")
			typ.len = -1
		}
		typ.elem = check.varType(e.Elem)
		if typ.len >= 0 {
			return typ
		}
		// 遇到[…]时报告错误

	case *syntax.SliceType:
		typ := new(Slice)
		def.setUnderlying(typ)
		typ.elem = check.varType(e.Elem)
		return typ

	case *syntax.DotsType:
		// 点在合法的位置显式处理
		// （数组复合文字和参数列表）
		check.error(e, "invalid use of '...'")
		check.use(e.Elem)

	case *syntax.StructType:
		typ := new(Struct)
		def.setUnderlying(typ)
		check.structType(typ, e)
		return typ

	case *syntax.Operation:
		if e.Op == syntax.Mul && e.Y == nil {
			typ := new(Pointer)
			typ.base = Typ[Invalid] // 在无效的递归类型声明中避免零基
			def.setUnderlying(typ)
			typ.base = check.varType(e.X)
			// 如果类型为。base无效，base不太可能是
			// 有用-即使是有效的取消引用也会导致无效的
			// 再次键入，在某些情况下，我们会遇到意外的后续错误
			// （例如，请参见#49005）。返回无效的类型。
			if typ.base == Typ[Invalid] {
				return Typ[Invalid]
			}
			return typ
		}

		check.errorf(e0, "%s is not a type", e0)
		check.use(e0)

	case *syntax.FuncType:
		typ := new(Signature)
		def.setUnderlying(typ)
		check.funcType(typ, nil, nil, e)
		return typ

	case *syntax.InterfaceType:
		typ := check.newInterface()
		def.setUnderlying(typ)
		if def != nil {
			typ.obj = def.obj
		}
		check.interfaceType(typ, e, def)
		return typ

	case *syntax.MapType:
		typ := new(Map)
		def.setUnderlying(typ)

		typ.key = check.varType(e.Key)
		typ.elem = check.varType(e.Value)

		// 规范：“对于键类型的操作数，比较运算符==和！=必须是完全定义的
		// 因此键类型不能是
		// 函数、映射或切片。”
		// 
		// 延迟此检查，因为它需要完全设置类型；
		// 在任何情况下都可以继续（was第6667期）。
		check.later(func() {
			if !Comparable(typ.key) {
				var why string
				if isTypeParam(typ.key) {
					why = " (missing comparable constraint)"
				}
				check.errorf(e.Key, "invalid map key type %s%s", typ.key, why)
			}
		})

		return typ

	case *syntax.ChanType:
		typ := new(Chan)
		def.setUnderlying(typ)

		dir := SendRecv
		switch e.Dir {
		case 0:
			// 无需操作
		case syntax.SendOnly:
			dir = SendOnly
		case syntax.RecvOnly:
			dir = RecvOnly
		default:
			check.errorf(e, invalidAST+"unknown channel direction %d", e.Dir)
			// 继续
		}

		typ.dir = dir
		typ.elem = check.varType(e.Elem)
		return typ

	default:
		check.errorf(e0, "%s is not a type", e0)
		check.use(e0)
	}

	typ := Typ[Invalid]
	def.setUnderlying(typ)
	return typ
}

func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *Named) (res Type) {
	if check.conf.Trace {
		check.trace(x.Pos(), "-- instantiating %s with %s", x, xlist)
		check.indent++
		defer func() {
			check.indent--
			// 请不要在此处设置基础格式。它将永远是零。
			check.trace(x.Pos(), "=> %s", res)
		}()
	}

	gtyp := check.genericType(x, true)
	if gtyp == Typ[Invalid] {
		return gtyp // 已报告错误
	}

	orig, _ := gtyp.(*Named)
	if orig == nil {
		panic(fmt.Sprintf("%v: cannot instantiate %v", x.Pos(), gtyp))
	}

	// 评估参数
	targs := check.typeList(xlist)
	if targs == nil {
		def.setUnderlying(Typ[Invalid]) // 避免延迟实例化导致的错误
		return Typ[Invalid]
	}

	// 启用类型推断控制是否推断缺少的类型参数
	// 使用约束类型推断。见第51527期。
	const enableTypeTypeInference = false

	// 创建实例
	ctxt := check.bestContext(nil)
	h := ctxt.instanceHash(orig, targs)
	// 目标可能不完整，需要推断。无论如何，我们都应该消除重复。
	inst, _ := ctxt.lookup(h, orig, targs).(*Named)
	// 如果inst为非零，我们不能直接返回这里。Inst可能是通过递归替换构造的
	// 在这种情况下，我们不会进行下面的
	// 验证。确保对源中的每个实例化类型运行
	// 验证（以及由此产生的错误）。
	if inst == nil {
		// x可以是导入类型的选择器；使用其起始位置，而不是x.pos（）。
		tname := NewTypeName(syntax.StartPos(x), orig.obj.pkg, orig.obj.name, nil)
		inst = check.newNamed(tname, orig, nil, nil, nil) // 解析命名时会设置基础、方法和Tparam 
		inst.targs = newTypeList(targs)
		inst = ctxt.update(h, orig, targs, inst).(*Named)
	}
	def.setUnderlying(inst)

	inst.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, *methodList) {
		tparams := n.orig.TypeParams().list()

		targs := n.targs.list()
		if enableTypeTypeInference && len(targs) < len(tparams) {
			// 如果推理失败，len（推断）将为0，inst.undernative将
			// 在expandNamed中设置为Typ[Invalid]。
			inferred := check.infer(x.Pos(), tparams, targs, nil, nil)
			if len(inferred) > len(targs) {
				n.targs = newTypeList(inferred)
			}
		}

		return expandNamed(ctxt, n, x.Pos())
	}

	// 原版。tparams可能无法设置，因此我们需要稍后进行扩展。
	check.later(func() {
		// 这是源代码的实例，而不是递归替换的实例，因此必须在类型检查期间解决它，以便我们可以报告
		// 错误。
		inst.resolve(ctxt)
		// 由于check是非零的，所以我们仍然可以对其进行变异。解钉解析器
		// 可以释放一些内存。
		inst.resolver = nil
		check.recordInstance(x, inst.TypeArgs().list(), inst)

		if check.validateTArgLen(x.Pos(), inst.tparams.Len(), inst.targs.Len()) {
			if i, err := check.verify(x.Pos(), inst.tparams.list(), inst.targs.list()); err != nil {
				// 错误报告的最佳位置
				pos := x.Pos()
				if i < len(xlist) {
					pos = syntax.StartPos(xlist[i])
				}
				check.softErrorf(pos, "%s", err)
			} else {
				check.mono.recordInstance(check.pkg, x.Pos(), inst.tparams.list(), inst.targs.list(), xlist)
			}
		}

		check.validType(inst)
	})

	return inst
}

// arrayLength类型检查数组长度表达式e 
// 并返回常量长度>=0，或一个值<0 
// 以指示错误（因此是未知长度）。
func (check *Checker) arrayLength(e syntax.Expr) int64 {
	// 如果e是标识符，则数组声明可能是
	// 尝试使用缺少
	// 约束的参数化类型声明。提供一条提到数组
	// 长度的错误消息。
	if name, _ := e.(*syntax.Name); name != nil {
		obj := check.lookup(name.Value)
		if obj == nil {
			check.errorf(name, "undeclared name %s for array length", name.Value)
			return -1
		}
		if _, ok := obj.(*Const); !ok {
			check.errorf(name, "invalid array length %s", name.Value)
			return -1
		}
	}

	var x operand
	check.expr(&x, e)
	if x.mode != constant_ {
		if x.mode != invalid {
			check.errorf(&x, "array length %s must be constant", &x)
		}
		return -1
	}

	if isUntyped(x.typ) || isInteger(x.typ) {
		if val := constant.ToInt(x.val); val.Kind() == constant.Int {
			if representableConst(val, check, Typ[Int], nil) {
				if n, ok := constant.Int64Val(val); ok && n >= 0 {
					return n
				}
				check.errorf(&x, "invalid array length %s", &x)
				return -1
			}
		}
	}

	check.errorf(&x, "array length %s must be integer", &x)
	return -1
}

// typeList提供与传入表达式列表相对应的类型列表。
// 如果发生错误，结果为零，但所有列表元素都经过了类型检查。
func (check *Checker) typeList(list []syntax.Expr) []Type {
	res := make([]Type, len(list)) // res！=即使len（list）==0 
	for i, x := range list {
		t := check.varType(x)
		if t == Typ[Invalid] {
			res = nil
		}
		if res != nil {
			res[i] = t
		}
	}
	return res
}
